package net.telesing.tcmc.back.logic;

import java.io.File;
import java.sql.Date;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.telesing.tcmc.back.dao.CertificateDao;
import net.telesing.tcmc.back.model.CertificateModel;
import net.telesing.tcmc.back.model.SectionModel;
import net.telesing.tcmc.back.model.UserModel;
import net.telesing.tcmc.common.Constants;
import net.telesing.tcmc.common.DropModel;
import net.telesing.tcmc.core.HttpUtil;
import net.telesing.tcmc.core.StringUtil;
import net.telesing.tcmc.core.TimeUtil;
import net.telesing.tcmc.core.utils.FileUtil;
import net.telesing.tcmc.core.web.Ajax;
import net.telesing.tcmc.core.web.AjaxBean;
import net.telesing.tsdk.tlib.Acomms;
import net.telesing.tsdk.tlib.CerInfor;

import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.nutz.dao.Cnd;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;

/**
 * 证书管理相关Logic
 *
 * Created by Zmt on 2015/11/3.
 */
@IocBean
public class CertificateLogic
{
    private static final Logger log = LogManager.getLogger(CertificateLogic.class);

    private static final String CER_TIME_SQL = "SELECT COUNT(*) FROM `tsc_certificate` WHERE `SID`=%s AND `CRT_TIME` >= '%s'";

    @Inject
    private CertificateDao certificateDao;

    /**
     * 查询对应号段下的证书
     *
     * @param sId
     * @return
     */
    public List<CertificateModel> queryCertificate(long sId)
    {
        return certificateDao.query(CertificateModel.class, Cnd.where("SID", "=", sId).desc("ID"));
    }

    /**
     * 申请证书
     *
     * @param user
     * @param certificateModel
     */
    public AjaxBean apply(long user, CertificateModel certificateModel, HttpServletRequest httpServletRequest)
    {
        AjaxBean result = Ajax.fail().setMsg(Constants.DATA_EXCEPTION);
        try
        {
            long sid = certificateModel.getSid();
            synchronized (CertificateLogic.class)
            {
                double todayNum = certificateDao.executeSql(String.format(CER_TIME_SQL, sid, TimeUtil.getFutureDate(0)));
                if (todayNum < 3)
                {
                    SectionModel sectionModel = certificateDao.fetch(SectionModel.class, sid);
                    if (null != sectionModel)
                    {
                        String oName = sectionModel.getOrgName();
                        String sName = sectionModel.getName();
                        if (null != oName && null != sName)
                        {
                            Date svd = sectionModel.getValidDate();
                            long svd_code = TimeUtil.transformTime(svd);
                            if (svd_code >= TimeUtil.getFutureTime(7))
                            {
                                String secretStr = null;
                                String userIp = HttpUtil.getIpAddress(httpServletRequest);
                                Date cvd = TimeUtil.formatDate(TimeUtil.getFutureTime(7));
//                            Date final_vd = (null != sectionModel.getValidDate() && TimeUtil.checkDate(svd, cvd)) ? svd : cvd;
                                certificateModel.setPath(String.format(Constants.CER_RELATIVE_PATH, oName, sName, sName + "_" + generateSalt(6)));
                                certificateModel.setIp(HttpUtil.getIpAddress(httpServletRequest));
                                certificateModel.setValidDate(cvd);
                                String mOrg = certificateModel.getmOrg();
                                if (mOrg == null || mOrg.equals(""))
                                    certificateModel.setmOrg("empty");
                                CertificateModel firstCer = certificateDao.insert(certificateModel, user);
                                String secContent = null;
                                // 判断操作系统
//                            if (StringUtil.isLinux())
                                {
                                    CerInfor cer_temp = new CerInfor();
                                    cer_temp.setSection(sName);
                                    cer_temp.setExpiration(cvd.toString());
                                    cer_temp.setAuthority(String.valueOf(certificateModel.getType()));
                                    cer_temp.setGenrTime(TimeUtil.formatDate(System.currentTimeMillis()).toString());
                                    cer_temp.setGenrType(String.valueOf(firstCer.getOrigin()));
                                    cer_temp.setID(String.valueOf(firstCer.getId()));
                                    cer_temp.setOrgID(String.valueOf(sectionModel.getOrgId()));
                                    cer_temp.setGenrIp(userIp);
                                    cer_temp.setSectSrc(firstCer.getmOrg());
                                    Acomms acomms = Acomms.getInstance();
                                    synchronized (acomms)
                                    {
                                        secretStr = acomms.encryptCer(cer_temp);  // JNI调用c++方法，加密证书信息
                                    }
                                }
//                        String secret = new BASE64Encoder().encode(new KeyUtil().getUtil().publicEncrypt(generateString(sectionModel, false), Constants.PUBLIC_KEY_PATH));
                                firstCer.setContent(secretStr);
                                certificateDao.update(firstCer);
                                result = Ajax.ok().setData(firstCer);
                            }
                            else if (svd_code >= System.currentTimeMillis())  // 如果码段未过期，但有效期距离当前时间不足7天
                                result = Ajax.fail().setMsg(Constants.SECTION_DATE_SHORT);
                            else if(svd_code < System.currentTimeMillis())  // 如果码段已过期
                                result = Ajax.fail().setMsg(Constants.SECTION_OUT_DATE);
                        }
                    }
                }
                else
                    result = Ajax.fail().setMsg(Constants.LIMIT_EXCEEDED_WORD);
            }
        }
        catch (Exception e)
        {
            e.printStackTrace();
            result = Ajax.fail().setMsg(e.getMessage());
        }
        return result;
    }

    /**
     * 批量删除证书
     *
     * @param ids
     */
    public AjaxBean delete(long[] ids)
    {
        AjaxBean result;
        try
        {
            for (long id : ids)
            {
                CertificateModel model = certificateDao.fetch(CertificateModel.class, id);
                if (null != model && null != model.getPath())
                {
                    File file = new File(model.getPath());
                    if (file.exists())
                        file.getAbsoluteFile().delete();
                }
                certificateDao.delete(CertificateModel.class, id);
            }
            result = Ajax.ok();
        }
        catch (Exception e)
        {
            e.printStackTrace();
            result = Ajax.fail().setMsg(e.getMessage());
        }
        return result;
    }

    /**
     * 删除证书
     *
     * @param id
     */
    public AjaxBean delete(long id)
    {
        AjaxBean result;
        try
        {
            CertificateModel model = certificateDao.fetch(CertificateModel.class, id);
            if (null != model && null != model.getPath())
            {
                File file = new File(model.getPath());
                if (file.exists())
                    file.getAbsoluteFile().delete();
            }
            certificateDao.delete(CertificateModel.class, id);
            result = Ajax.ok();
        }
        catch (Exception e)
        {
            e.printStackTrace();
            result = Ajax.fail().setMsg(e.getMessage());
        }
        return result;
    }
    
    /**
     * 修改码段信息（局部）
     *
     * @param sectionModel
     * @param sid
     * @param user
     * @return
     */
    public AjaxBean modifyLocalSection(SectionModel sectionModel, long sid, UserModel user)
    {
        SectionModel section = certificateDao.fetch(SectionModel.class, sid);
        section.setSource(sectionModel.getSource());
        section.setSkipPath(sectionModel.getSkipPath());
        certificateDao.update(section, user.getId());
        return Ajax.ok();
    }

    /**
     * 下载证书文件
     *
     * @param response
     * @param ids
     * @return
     */
    public File download(HttpServletResponse response, long[] ids)
    {
        File file = null;
        response.setHeader("Accept-Ranges", "bytes");
        if (1 == ids.length)
        {
            String path = Constants.CER_BASE_PATH + certificateDao.fetch(CertificateModel.class, ids[0]).getPath();
            response.setHeader("Content-Disposition", "attachment;filename=" + path.substring(path.lastIndexOf(Constants.SLASH) + 1));
            file = new File(path);
        }
        else if (1 < ids.length)
        {
            response.setHeader("Content-Disposition", "attachment;filename=keys.zip");
            File[] files = new File[ids.length];
            File key;
            for (int i = 0; i < ids.length; i++)
            {
                key = new File(Constants.CER_BASE_PATH + certificateDao.fetch(CertificateModel.class, ids[i]).getPath());
                files[i] = key;
            }
            if (new FileUtil().getUtil().packFiles(files, Constants.PACKAGE_PATH))
                file = new File(Constants.PACKAGE_PATH);
        }
        return file;
    }

    /**
     * 下载证书文件
     *
     * @param response
     * @param id
     * @return
     */
    public File download(HttpServletResponse response, long id)
    {
        response.setHeader("Accept-Ranges", "bytes");
        CertificateModel cer = certificateDao.fetch(CertificateModel.class, id);
        String path = Constants.CER_BASE_PATH + cer.getPath();
        try
        {
            new FileUtil().getUtil().generateFile(path, cer.getContent());
        }
        catch (Exception e)
        {
            e.printStackTrace();
            log.error("证书生成异常！");
        }
        response.setHeader("Content-Disposition", "attachment;filename=" + path.substring(path.lastIndexOf(Constants.SLASH) + 1));
        return new File(path);
    }
    
    /**
     * 生成证书内容
     * 
     * @param sectionModel
     * @param isFinal
     * @return
     */
    private String generateString(SectionModel sectionModel, boolean isFinal)
    {
        String flag = "|";
        String name = sectionModel.getName();
        Date validDate = sectionModel.getValidDate();
        String orgName = sectionModel.getOrgName();
        return (!isFinal)
                ? (name
                + flag 
                + complementString(16, sectionModel.getId().intValue())
                + flag 
                + ((null != validDate) ? String.valueOf(validDate).replaceAll("\\-", "") : "00000000")
                + flag 
                + generateSalt(15))
                : (name
                    + flag
                    + ((null != validDate) ? String.valueOf(validDate).replaceAll("\\-", "") : "00000000")
                    + flag
                    + ((null != orgName) ? orgName : "")
                    + flag);
    }

    /**
     * 生成盐
     *
     * @return
     */
    private String generateSalt(int length)
    {
        Random r = new Random();
        Double d = r.nextDouble();
        return String.valueOf(d).substring(3, 3 + length);
    }

    /**
     * 补足位数（用0补足）
     *
     * @param length
     * @param number
     * @return
     */
    private String complementString(int length, int number)
    {
        String f = "%0" + length + "d";
        return String.format(f, number);
    }

    /**
     * 生成证书类型下拉框内容
     *
     * @return
     */
    public List<DropModel> getCerType()
    {
        return new ArrayList<DropModel>(){
            {
                add(new DropModel("生成证书", 1));
                add(new DropModel("识别证书", 2));
                add(new DropModel("全部证书", 3));
            }
        };
    }

}
